package it.patamau.bukkit;

import java.io.IOException;
import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;

public abstract class AbstractPlugin extends JavaPlugin {
	
	//retrieve minecraft logger
	private final static Logger LOGGER = Logger.getLogger("Minecraft");
	
	// user level messages
	private PluginMessages messages;
	// internally used to identify logging messages
	private String logPrefix;
	// internally used to store parameters
	private PluginParameters pluginParameters;
	// the plugin description
	protected PluginDescriptionFile description;
    
	/**
	 * Attach the shutdown hook and call init
	 */
    public AbstractPlugin(){
    	//attach shutdown hook (?)
		//Runtime.getRuntime().addShutdownHook(new PluginShutdownHook(this));
	}
    
    /**
     * Used to load the description file
     * and log initialization message
     */
    protected void initialize(PluginParameters parameters){
    	pluginParameters = parameters;
        description = this.getDescription();
        if(description!=null){	   
	        logPrefix = "["+description.getName()+"] ";
			StringBuffer m = new StringBuffer();
			m.append(description.getFullName());
			m.append(" by ");
			int s = description.getAuthors().size();
			for(int i=0; i<s; i++){
				m.append(description.getAuthors().get(i));
				if(i<(s-1)){
					m.append(", ");
				}
			}
			log(m.toString());
        }else{
        	String n = this.getClass().getSimpleName();
        	logPrefix = "["+n+"] ";
        	log("Error loading plugin description");
        	log(n);
        }
        
    	messages = new PluginMessages(this);
    	try {
			messages.load();
		} catch (IOException e) {
			e.printStackTrace();
		}

		log("loaded "+messages.size()+" messages");
    }
    
    public String evaluateTest(String msg){
    	MessageFormat test = new MessageFormat("{1}?{2}:{3}");
    	try {
			Object[] args = test.parse(msg);
			if(args.length==3){
				if(Boolean.parseBoolean((String)args[0])){
					return (String)args[1];
				}else{
					return (String)args[2];
				}
			}else{
				log(Level.WARNING,"unable to evaluate conditional message >"+msg+"<");
			}
		} catch (ParseException e) {
			//no test to parse, skip it
		}
		return msg;
    }
    
	public String injectParams(String msg, Player player){
		String str = msg;
		if(player!=null){
			str = str.replaceAll("\\$player", player.getDisplayName());
			str = str.replaceAll("\\$op", Boolean.toString(player.isOp()));
			str = str.replaceAll("\\$version", description.getVersion());
		}
		if(pluginParameters!=null){
			for(Field f: pluginParameters.getAffectedFields()){
				Object o;
				try {
					o = f.get(pluginParameters);
					if(o!=null){
						str = str.replaceAll("\\$"+f.getName(), o.toString());
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
		str = evaluateTest(str);
		return str;
	}
    
    public PluginMessages getMessages(){
    	return messages;
    }
    
    /**
     * Retrieved a formatted message
     * the message is customized with parameters and given player
     * colors are already assumed to be stored
     * @param key
     * @param player
     * @return
     */
    public String getFormattedMessage(String key, Player player, Object ... args){
    	String m = messages.get(key, args);
    	return injectParams(m, player);
    }
    
    /**
     * Send message to the given entity (consider Player)
     * @param sender
     * @param key
     */
    public void sendMessage(String key, CommandSender sender, Object ... args){
    	Player p = null;
    	if(sender instanceof Player){
    		p = (Player)sender;
    	}
    	String m = getFormattedMessage(key, p, args);
    	if(m.length()>0){
    		sender.sendMessage(m);
    	}
    }
    
    /**
     * Send a message to all players
     * @param key
     * @param args
     */
    public void broadcastMessage(String key, Object ... args){
    	String m = getFormattedMessage(key, null, args);
    	if(m.length()>0){
    		this.getServer().broadcastMessage(m);
    	}
    }
    
    /**
     * Send a message to all players but the one specified
     * @param key
     * @param but
     * @param args
     */
    public void broadcastMessage(String key, CommandSender but, Object ... args){
       	String m = getFormattedMessage(key, null, args);
    	if(m.length()>0){
    		for(Player p: this.getServer().getOnlinePlayers()){
    			if(p!=but){
    				p.sendMessage(m);
    			}
    		}
    	}
    }
    
    /**
     * Log info messages
     * @param message
     */
    public final void log(String message){
    	log(Level.INFO, message);
    }
    
    /**
     * Log messages to standard logger
     * @param level
     * @param message
     */
    public final void log(Level level, String message){
    	LOGGER.log(level,logPrefix+message);
    }

	public void onDisable() {
		log("disabled");
	}

	public void onEnable() {
		log("enabled");
	}
}
